#include <thread>
#include <future>

#include "../../include/CLink/database/DatabaseManager.h"


namespace CLink {
namespace Db {

void DatabaseManager::initialize(const ConnectionConfig& config) {
    try {
        _pool = std::make_unique<ConnectionPool>(config);
#ifdef _WIN32
        if (config.type == DatabaseType::MYSQL)
        {
            _last_insert = "LAST_INSERT_ID()";
        }
        else 
#endif
        if(config.type == DatabaseType::SQLITE)
        {
            _last_insert = "LAST_INSERT_ROWID()";
        }
        else
        {
            throw DatabaseException("not surport database type",
                                  DatabaseErrorCode::UNSUPPORTED_DATABASE_TYPE);
        }
    } catch (const std::exception& e) {
        throw DatabaseException("init databasemanager error: " + std::string(e.what()),
                              DatabaseErrorCode::CONNECTION_FAILED);
    }
}

void DatabaseManager::shutdown() {
    if (_pool) {
        _pool->shutdown();
        _pool.reset();
    }
}

QueryBuilder DatabaseManager::getQueryBuilder() {
    return QueryBuilder();
}

ResultSet DatabaseManager::query(const std::string& sql) {
    return executeWithConnection<ResultSet>([&](Connection& conn) {
        try {
            Poco::Data::Statement stmt(conn.getSession());
            stmt << sql;
            stmt.execute();
            return ResultSet(Poco::Data::RecordSet(stmt));
        } catch (const Poco::Exception& e) {
            throw QueryException("执行查询失败: " + std::string(e.what()));
        }
    });
}

ResultSet DatabaseManager::query(const QueryBuilder& builder) {
    return query(builder.build());
}

size_t DatabaseManager::execute(const std::string& sql) {
    return executeWithConnection<size_t>([&](Connection& conn) {
        try {
            Poco::Data::Statement stmt(conn.getSession());
            stmt << sql;
            return stmt.execute();
        } catch (const Poco::Exception& e) {
            throw QueryException("执行更新失败: " + std::string(e.what()));
        }
    });
}

size_t DatabaseManager::execute(const QueryBuilder& builder) {
    return execute(builder.build());
}

AsyncResult<ResultSet> DatabaseManager::queryAsync(const std::string& sql) {
    return executeAsyncWithConnection<ResultSet>([this, sql](Connection& conn) {
        return this->query(sql);
    });
}

AsyncResult<ResultSet> DatabaseManager::queryAsync(const QueryBuilder& builder) {
    return queryAsync(builder.build());
}

AsyncResult<size_t> DatabaseManager::executeAsync(const std::string& sql) {
    return executeAsyncWithConnection<size_t>([this, sql](Connection& conn) {
        return this->execute(sql);
    });
}

AsyncResult<size_t> DatabaseManager::executeAsync(const QueryBuilder& builder) {
    return executeAsync(builder.build());
}

Transaction DatabaseManager::beginTransaction(IsolationLevel level) {
    auto conn = _pool->getConnection();
    return Transaction(conn, level);
}

template<typename Container>
void DatabaseManager::batch(const std::string& sql, const Container& params) {
    executeWithConnection<void>([&](Connection& conn) {
        try {
            Poco::Data::Statement stmt(conn.getSession());
            stmt << sql;
            
            for (const auto& param : params) {
                stmt.execute();
            }
        } catch (const Poco::Exception& e) {
            throw QueryException("执行批量操作失败: " + std::string(e.what()));
        }
    });
}

int64_t DatabaseManager::lastInsertId() {
    return executeWithConnection<int64_t>([this](Connection& conn) {
        try {
            Poco::Data::Statement stmt(conn.getSession());
            stmt << "SELECT " + _last_insert;
            int64_t id = 0;
            stmt.execute();
            id = Poco::Data::RecordSet(stmt)[0].extract<int64_t>();
            return id;
        } catch (const Poco::Exception& e) {
            throw QueryException("获取最后插入ID失败: " + std::string(e.what()));
        }
    });
}

size_t DatabaseManager::affectedRows() {
    return executeWithConnection<size_t>([](Connection& conn) {
        try {
            Poco::Data::Statement stmt(conn.getSession());
            stmt << "SELECT ROW_COUNT()";
            size_t rows = 0;
            stmt.execute();
            rows = Poco::Data::RecordSet(stmt)[0].extract<size_t>();
            return rows;
        } catch (const Poco::Exception& e) {
            throw QueryException("获取影响行数失败: " + std::string(e.what()));
        }
    });
}

bool DatabaseManager::tableExists(const std::string& tableName) {
    return executeWithConnection<bool>([&](Connection& conn) {
        try {
            std::string tmp = tableName;
            Poco::Data::Statement stmt(conn.getSession());
            stmt << "SELECT 1 FROM information_schema.tables "
                   "WHERE table_schema = DATABASE() AND table_name = ?",
                Poco::Data::Keywords::use(tmp);
            stmt.execute();
            return Poco::Data::RecordSet(stmt).rowCount() > 0;
        } catch (const Poco::Exception& e) {
            throw QueryException("检查表是否存在失败: " + std::string(e.what()));
        }
    });
}

std::vector<FieldDefinition> DatabaseManager::getTableSchema(const std::string& tableName) {
    return executeWithConnection<std::vector<FieldDefinition>>([&](Connection& conn) {
        try {
            std::vector<FieldDefinition> fields;
            Poco::Data::Statement stmt(conn.getSession());
            
            std::string tmp = tableName;

            stmt << "SELECT column_name, data_type, is_nullable, "
                   "column_key, extra, column_default, character_maximum_length "
                   "FROM information_schema.columns "
                   "WHERE table_schema = DATABASE() AND table_name = ?",
                Poco::Data::Keywords::use(tmp);
            
            stmt.execute();
            
            Poco::Data::RecordSet rs(stmt);
            while (!rs.moveNext()) {
                FieldDefinition field;
                field.name = rs["column_name"].convert<std::string>();
                
                std::string dataType = rs["data_type"].convert<std::string>();
                if (dataType == "int" || dataType == "bigint") {
                    field.type = FieldType::INTEGER;
                } else if (dataType == "float" || dataType == "double") {
                    field.type = FieldType::FLOAT;
                } else if (dataType == "varchar" || dataType == "text") {
                    field.type = FieldType::TEXT;
                } else if (dataType == "datetime") {
                    field.type = FieldType::DATETIME;
                } else if (dataType == "tinyint") {
                    field.type = FieldType::BOOLEAN;
                } else {
                    field.type = FieldType::BLOB;
                }
                
                field.nullable = rs["is_nullable"].convert<std::string>() == "YES";
                field.primary = rs["column_key"].convert<std::string>() == "PRI";
                field.autoIncrement = rs["extra"].convert<std::string>().find("auto_increment") != std::string::npos;
                
                if (!rs["column_default"].isEmpty()) {
                    field.defaultValue = rs["column_default"].convert<std::string>();
                }
                
                if (!rs["character_maximum_length"].isEmpty()) {
                    field.length = rs["character_maximum_length"].convert<size_t>();
                }
                
                fields.push_back(field);
            }
            
            return fields;
        } catch (const Poco::Exception& e) {
            throw QueryException("获取表结构失败: " + std::string(e.what()));
        }
    });
}

std::string DatabaseManager::escape(const std::string& str) {
    std::string result;
    result.reserve(str.length() * 2);
    
    for (char c : str) {
        switch (c) {
            case '\'':
                result += "''";
                break;
            case '\\':
                result += "\\\\";
                break;
            case '\n':
                result += "\\n";
                break;
            case '\r':
                result += "\\r";
                break;
            case '\t':
                result += "\\t";
                break;
            default:
                result += c;
                break;
        }
    }
    
    return result;
}

template<typename T>
T DatabaseManager::executeWithConnection(std::function<T(Connection&)> callback) {
    auto conn = _pool->getConnection();
    return callback(*conn);
}

template<typename T>
AsyncResult<T> DatabaseManager::executeAsyncWithConnection(std::function<T(Connection&)> callback) {
    return AsyncResult<T>(std::async(std::launch::async, [this, callback]() {
        auto conn = _pool->getConnection();
        return callback(*conn);
    }));
}

} // namespace db
} // namespace CLink